#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

struct Rect {
  int width;
  int height;

  Rect(int w, int h) : width(w), height(h) {}
};


/**
 * 一开始我是想遍历每行，找到每行连续的矩形，
 * 然后记录在一个数组中
 * 
 * 如果上一行存在数组，那么和上一行的进行合并，
 * 合并之后然后求出最大的面积
 * 
 * 这里的关键点在于如何合并，我首先的想法是合并两个有序的矩形数组，
 * 后来我发现并不需要先合并再求面积，联想到之前的求最大矩形的题目，
 * 可以先累计每行的每个格子的高度，然后转化到之前那个题目就可以了
 */ 
class Solution {
public:
  // 时间复杂度为 O(mn)
  int maximalRectangle(vector< vector<char> > &matrix) {
    int maxArea = 0;

    if (matrix.size() < 1) {
      return 0;
    }

    vector<int> heights(matrix[0].size(), 0);

    for (int i = 0; i < matrix.size(); i++) {
      for (int j = 0; j < matrix[i].size(); j++) {
        // 累加矩形的高度，当为 0 时则中止
        if (matrix[i][j] == '0') {
          heights[j] = 0;
        } else {
          heights[j] += 1;
        }
      }

      // 转化为一维的求最大矩形面积
      maxArea = max(maxArea, largestRectangleArea(heights));
    }

    return maxArea;
  }

private:
  int largestRectangleArea(vector<int> &heights) {
    // 最大矩形的面积
    int maxArea = 0;

    // 单调递增栈
    stack<Rect> s;

    // 最后强制合并所有矩形，计算最大的面积
    heights.push_back(0);

    for (int i = 0; i < heights.size(); i++) {
      int height = heights[i];
      int accumulatedWidth = 0;

      // 单调性被破坏
      while (!s.empty() && s.top().height >= height) {
        accumulatedWidth += s.top().width;
        maxArea = max(maxArea, s.top().height * accumulatedWidth);

        s.pop();
      }

      // 将栈里面高度 >= height 的矩形，
      // 与高度为 height 的矩形进行合并
      s.push(Rect(accumulatedWidth + 1, height));
    }

    return maxArea;
  }
};

int main() {
  vector< vector<char> > matrix;

  int row, col;

  cin >> row >> col;

  char number = 0;
  for (int i = 0; i < row; i++) {
    vector<char> rows;
    for (int j = 0; j < col; j++) {
      cin >> number;
      rows.push_back(number);
    }
    matrix.push_back(rows);
  }

  cout << Solution().maximalRectangle(matrix) << endl;

  return 0;
}